package com.sidneysimmons.financially;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.message.BasicNameValuePair;

import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.util.Log;

import com.sidneysimmons.financially.managers.UserManager;

public class Server extends BaseServer implements Runnable {
	
	private final String CLASS_NAME = this.getClass().getName();
	
	/*  Commands  */
	public final static int COMMAND_add_new_user = 12;
	public final static int COMMAND_validate_user_login = 18;
	public final static int COMMAND_forgotten_password_email = 24;
	
	/*  Responses  */
	public final static int RESPONSE_error = 1;
	public final static int RESPONSE_okay = 2;
	
	/*  Data to send to server  */
	HashMap map;
	
	private int command;
	private Handler handler;
	private Context context;
	
	/**
	 * This class is used for all communication between app and server.  Pass in a command, 
	 * and a map containing the values needed for that command.  Use the handler to send 
	 * messages back to the calling class or Activity.
	 * 
	 * @param command - int describing which method to call
	 * @param map - HashMap containing values
	 * @param handler - Handler to send back messages from Thread
	 */
	public Server(int command, HashMap map, Handler handler, Context context) {
		this.command = command;
		this.map = map;
		this.handler = handler;
		this.context = context;
	}
	
	@Override
	public void run() {
		if (command == COMMAND_add_new_user) {
			User newUser = new User();
			newUser.setEmailAddress((String) map.get("emailAddress"));
			newUser.setPassword((String) map.get("password"));
			
			addNewUser(newUser);
		} else if (command == COMMAND_validate_user_login) {
			User user = new User();
			user.setEmailAddress((String) map.get("emailAddress"));
			user.setPassword((String) map.get("password"));
			
			validateUserLogin(user);
		} else if (command == COMMAND_forgotten_password_email) {
			String emailAddress = (String) map.get("emailAddress");
			sendForgottenPasswordEmail(emailAddress);
		}
	}
	
	/**
	 * Add a new user to the Server database.
	 * 
	 * @param newUser - The User populated with email address and password.
	 */
	public void addNewUser(User newUser) {
		String emailAddress = newUser.getEmailAddress();
		String password = newUser.getPassword();
		
		if (emailAddress == null || password == null) {
			messageBack(RESPONSE_error, R.string.server_error_null_blank_input, null);
		}
		
		if (emailAddress.equals("") || password.equals("")) {
			messageBack(RESPONSE_error, R.string.server_error_null_blank_input, null);
		}
		
		String destination = "http://www.sidneysimmons.com/android/financially/procedures/create_user.php";
		List<NameValuePair> pairs = new ArrayList<NameValuePair>();
		pairs.add(new BasicNameValuePair("emailAddress", emailAddress));
		pairs.add(new BasicNameValuePair("password", password));
		
		HttpEntity response = sendMultiValue(destination, pairs);

		if (response != null) {
			try {
				InputStream is = response.getContent();
				BufferedReader reader = new BufferedReader(new InputStreamReader(is));
				
				// read the code and message from the server response
				int statusCode = Integer.parseInt(reader.readLine());
				String statusMessage = reader.readLine();
				Log.d(CLASS_NAME, "responseCode: " + statusCode);
				Log.d(CLASS_NAME, "responseMessage: " + statusMessage);
				
				if (statusCode == 3) {
					// Log user into Financially
					UserManager userManager = new UserManager(context);
					userManager.setCurrentUser(newUser);
					
					messageBack(RESPONSE_okay, R.string.server_okay_successful_add_new_user, null);
				} else if (statusCode == 2) {
					// Log user into Financially
					UserManager userManager = new UserManager(context);
					userManager.setCurrentUser(newUser);
					
					messageBack(RESPONSE_okay, R.string.server_okay_successful_add_new_user, null);
				} else if (statusCode == 1) {
					messageBack(RESPONSE_error, R.string.server_okay_user_already_exists, null);
				} else if (statusCode == 0) {
					messageBack(RESPONSE_error, R.string.server_error_server_side, null);
				}
				
			} catch (Exception e) {
				e.printStackTrace();
				messageBack(RESPONSE_error, R.string.server_error_reading_server_response, null);
			}
		} else {
			messageBack(RESPONSE_error, R.string.server_error_reading_server_response, null);
		}
	}
	
	/**
	 * Tells the server to email the user's password to their email address.
	 * 
	 * @param emailAddress - The email address of the user to email.
	 */
	public void sendForgottenPasswordEmail(String emailAddress) {
		if (emailAddress == null || emailAddress.equals("")) {
			messageBack(RESPONSE_error, R.string.server_error_null_blank_input, null);
		}
		
		String destination = "http://www.sidneysimmons.com/android/financially/procedures/forgot_password.php";
		List<NameValuePair> pairs = new ArrayList<NameValuePair>();
		pairs.add(new BasicNameValuePair("emailAddress", emailAddress));
		
		HttpEntity response = sendMultiValue(destination, pairs);
		
		if (response != null) {
			try {
				InputStream is = response.getContent();
				BufferedReader reader = new BufferedReader(new InputStreamReader(is));
				
				// read the code and message from the server response
				int statusCode = Integer.parseInt(reader.readLine());
				String statusMessage = reader.readLine();
				Log.d(CLASS_NAME, "responseCode: " + statusCode);
				Log.d(CLASS_NAME, "responseMessage: " + statusMessage);
				
				if (statusCode == 3) {
					messageBack(RESPONSE_okay, R.string.server_okay_forgotten_password_email_sent, null);
				} else if (statusCode == 2) {
					messageBack(RESPONSE_okay, R.string.server_okay_forgotten_password_problem_sending_email, null);
				} else if (statusCode == 1) {
					messageBack(RESPONSE_okay, R.string.server_okay_forgotten_password_user_does_not_exist, null);
				} else if (statusCode == 0) {
					messageBack(RESPONSE_error, R.string.server_error_server_side, null);
				}
			} catch (Exception e) {
				e.printStackTrace();
				messageBack(RESPONSE_error, R.string.server_error_reading_server_response, null);
			}
		} else {
			messageBack(RESPONSE_error, R.string.server_error_reading_server_response, null);
		}
	}
	
	/**
	 * Checks the server to find out if the email address/password combination exists.
	 * 
	 * @param user - The User populated with email address and password.
	 */
	public void validateUserLogin(User user) {
		String emailAddress = user.getEmailAddress();
		String password = user.getPassword();
		
		if (emailAddress == null || password == null) {
			messageBack(RESPONSE_error, R.string.server_error_null_blank_input, null);
		}
		
		if (emailAddress.equals("") || password.equals("")) {
			messageBack(RESPONSE_error, R.string.server_error_null_blank_input, null);
		}
		
		String destination = "http://www.sidneysimmons.com/android/financially/procedures/validate_user.php";
		List<NameValuePair> pairs = new ArrayList<NameValuePair>();
		pairs.add(new BasicNameValuePair("emailAddress", emailAddress));
		pairs.add(new BasicNameValuePair("password", password));
		
		HttpEntity response = sendMultiValue(destination, pairs);

		if (response != null) {
			try {
				InputStream is = response.getContent();
				BufferedReader reader = new BufferedReader(new InputStreamReader(is));
				
				// read the code and message from the server response
				int statusCode = Integer.parseInt(reader.readLine());
				String statusMessage = reader.readLine();
				Log.d(CLASS_NAME, "responseCode: " + statusCode);
				Log.d(CLASS_NAME, "responseMessage: " + statusMessage);
				
				if (statusCode == 2) {
					// Log user into Financially
					UserManager userManager = new UserManager(context);
					userManager.setCurrentUser(user);
					
					messageBack(RESPONSE_okay, R.string.server_okay_user_validation_successful, null);
				} else if (statusCode == 1) {
					messageBack(RESPONSE_okay, R.string.server_okay_user_validation_failed, null);
				} else if (statusCode == 0) {
					messageBack(RESPONSE_error, R.string.server_error_server_side, null);
				}
			} catch (Exception e) {
				e.printStackTrace();
				messageBack(RESPONSE_error, R.string.server_error_reading_server_response, null);
			}
		} else {
			messageBack(RESPONSE_error, R.string.server_error_reading_server_response, null);
		}
	}

	/**
	 * Sends a message back to the handler.<br><br>"what" indicates the command called.
	 * <br>"arg1" indicates the response code (error or okay).<br>"arg2" is a resource id 
	 * of a String that describes what happened.<br>"obj" might hold data.
	 * 
	 * @param response_code - int
	 * @param string_resource - String describing what happened
	 * @param data - Object
	 */
	private void messageBack(int response_code, int string_resource, Object data) {
		Message message = new Message();
		message.what = command;
		message.arg1 = response_code;
		message.arg2 = string_resource;
		message.obj = data;
		
		handler.sendMessage(message);
	}
}